﻿// <copyright file="CategoryRepository.cs" company="Auros Ltd.">
//     Copyright (c) Auros Ltd. All rights reserved.
// </copyright>

namespace Auros.Categorisation.Data
{
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Web;
    using System.Linq;

    /// <summary>
    /// Class defining the category repository for reading, updating and deleting categories.
    /// </summary>
    internal class CategoryRepository
    {
        private CategoryDAL categoryContext;

        /// <summary>
        /// Initializes a new instance of the <see cref="CategoryRepository"/> class using the Umbraco database connection string.
        /// </summary>
        public CategoryRepository()
        {
            this.categoryContext = new CategoryDAL(umbraco.BusinessLogic.Application.SqlHelper.ConnectionString);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="CategoryRepository"/> class.
        /// </summary>
        /// <param name="nameOrConnectionString">The name or connection string.</param>
        public CategoryRepository(string nameOrConnectionString)
        {
            this.categoryContext = new CategoryDAL(nameOrConnectionString);
        }

        /// <summary>
        /// Gets the root categories.
        /// </summary>
        /// <returns>Collection of category objects.</returns>
        public IEnumerable<Category> GetRootCategories()
        {
            return this.GetCategories(0);
        }

        /// <summary>
        /// Gets the categories.
        /// </summary>
        /// <param name="parentId">The parent id.</param>
        /// <returns>Collection of category objects.</returns>
        public IEnumerable<Category> GetCategories(int? parentId = null)
        {
            if (CategoryCache.Get().Count == 0)
            {
                CategoryCache.Add(DataHelpers.ConvertToCategory(this.categoryContext.GetAll()));
            }

            if (parentId.HasValue)
                return CategoryCache.Get().Where(category => category.ParentID == parentId);
            else
                return CategoryCache.Get();
        }

        /// <summary>
        /// Gets the category.
        /// </summary>
        /// <param name="id">The ID of the category to get.</param>
        /// <returns>Category with the specified ID.</returns>
        public Category GetCategory(int id)
        {
            return this.GetCategories().FirstOrDefault(cat => cat.ID == id);
        }

        /// <summary>
        /// Add the specified category.
        /// </summary>
        /// <param name="category">The category to add.</param>
        /// <returns>Newly created category with default or computed values set.</returns>
        public Category Add(Category category)
        {
            category.ID = this.categoryContext.Create(
                category.Name,
                category.Description,
                category.Selectable,
                category.Enabled,
                category.ParentID.GetValueOrDefault(0),
                category.SortOrder);

            if (category.ParentID.HasValue && category.ParentID.Value > 0 && !category.Parent.HasChildren)
            {
                category.Parent.HasChildren = true;
            }

            CategoryCache.Get().Add(category);

            return category;
        }

        /// <summary>
        /// Updates the specified category.
        /// </summary>
        /// <param name="category">The category to update.</param>
        public void Update(Category category)
        {
            this.categoryContext.Update(
                category.ID,
                category.Name,
                category.Description,
                category.Selectable,
                category.Enabled,
                category.ParentID.GetValueOrDefault(0),
                category.SortOrder);

            if (category.ParentID.HasValue && category.ParentID.Value > 0 && !category.Parent.HasChildren)
            {
                category.Parent.HasChildren = true;
            }
        }

        /// <summary>
        /// Deletes the category with the specified ID.
        /// </summary>
        /// <param name="id">The ID of the category to delete.</param>
        public void Delete(int id)
        {
            var cachedItem = CategoryCache.Get().FirstOrDefault(c => c.ID == id);

            if(cachedItem != null)
                CategoryCache.Get().Remove(cachedItem);

            this.categoryContext.Delete(id);
        }

        /// <summary>
        /// Deletes the specified category.
        /// </summary>
        /// <param name="category">The category.</param>
        public void Delete(Category category)
        {
            CategoryCache.Get().Remove(category);

            this.categoryContext.Delete(category.ID);
        }
    }
}